/***********************************************************************************
 * 文件名： mcu.c
 * 作者： 刘言
 * 版本： 1
 * 说明：
 * 		MCU 初始化
 * 修改记录：
 * 	2020/8/18: 初版。 刘言。
***********************************************************************************/
#include "mcu_top.h"


// 内部宏

#define TIMER_EVT  (1<<0)
#define LOAD_EVT    (1<<0)
#define LOOP_EVT    (1<<1)
#define WEAKUP_EVT  (1<<2)


// 内部属性

#if CFG_SLEEP_MODE == 2
static bool mLowPower = false;
#endif


// 需要调用的Polsys函数

void Polsys_Tick(void);
void Polsys_Loop(void); // 因为MCU驱动不会返回，所以在MCU驱动层调用
void App_Load(void);


// 内部函数声明

static void UserClkConfig();


// 以下是SDK内部的OSAL任务的初始化和任务执行函数 //////////////////////////////////////
// 调用 OSAL_Init 后以下函数将会得到执行
static u8 mUserLoopTaskID;

void UserLoop_Init( u8 task_id )
{
    mUserLoopTaskID = task_id;
    osal_set_event(mUserLoopTaskID, LOAD_EVT);  // 触发APP加载事件
    // LOG("UserLoop Inited.\r\n");
}

#if (CFG_SLEEP_MODE == 2)   // PWR_MODE_SLEEP
// MCU 成功退出低功耗蓝牙事件通知
WEAK void Mcu_EventExitLowPower()
{

}
#endif
// 最低优先级OSAL任务
u16 UserLoop( u8 task_id, u16 events )
{
    if(events & LOAD_EVT)   // APP加载事件，上电后只执行一次
    {
        // LOG("Polsys App Loaded.\r\n");
        SysTick_Config(SYSTICK_VALUE);  // 配置并启动 SysTick 定时器，开始执行Polsys的任务。
        osal_set_event(mUserLoopTaskID, LOOP_EVT);  // 触发LOOP事件。 进行polsys就绪任务扫描
#if (CFG_SLEEP_MODE == 2)   // PWR_MODE_SLEEP
        // hal_pwrmgr_lock(MOD_USR8);  // 使芯片无法进入到SLEEP模式
#endif
        UserClkConfig();
        App_Load();
        return (events ^ LOAD_EVT);
    }
#if (CFG_SLEEP_MODE == 2)   // PWR_MODE_SLEEP
    if(events & WEAKUP_EVT)
    {
        SysTick_Config(SYSTICK_VALUE);  // 重新配置并启动 SysTick 定时器。这个芯片休眠后会丢失外设配置。
        // hal_pwrmgr_lock(MOD_USR8);  // 使芯片无法进入到SLEEP模式
        osal_set_event(mUserLoopTaskID, LOOP_EVT);  // 进行polsys就绪任务扫描
        Mcu_EventExitLowPower();
        return (events ^ WEAKUP_EVT);
    }
#endif
    if(events & LOOP_EVT)
    {
#if (CFG_SLEEP_MODE == 2)   // PWR_MODE_SLEEP
        if(mLowPower)
        {
            return (events ^ LOOP_EVT);     // 不再执行 UserLoop ，SDK将进入低功耗
        }
        else
        {
            Polsys_Loop();
            return events;  // 继续不断执行
        }
#else
        Polsys_Loop();
#ifndef _MCU_DEBUG
        Wdt_Clear();
#endif
        return events;  // 不断执行
#endif
    }
    return 0;
}
//////////////////////////////////////////////////////////////////////////////////////

// void HalSysTickHander(void);
// SysTick 中断服务函数，该函数实际被芯片内置的MaskROM调用（中断向量表固定在MaskROM）。
WEAK void HalSysTickHander(void)
{
    Polsys_Tick();
}

void Mcu_Init(void)
{
    // 初始化SDK
    SDK_Init();
    // 重定向 SYSTICK_HANDLER
    JUMP_FUNCTION(SYSTICK_HANDLER) = (uint32_t)&HalSysTickHander; 
    // 如果需要重定向其它中断入口，在这里继续添加。
}

#if CFG_SLEEP_MODE == 2
void Mcu_EnterLowPower()
{
    mLowPower = true;
    // hal_pwrmgr_unlock(MOD_USR8);
}

void Mcu_ExitLowPower()
{
    if(mLowPower)
    {
        mLowPower = false;
        osal_set_event(mUserLoopTaskID, WEAKUP_EVT);
    }
}
#else

#endif


void Mcu_SetSysClkSrc(sysclk_t new_clk_src)
{
    g_system_clk = new_clk_src;
    clk_init(g_system_clk); ///< system init
}


// 内部函数

// 用户时钟配置，此时SDK已经初始化，polsys已经开始运行（只是还没有任务），在执行App_Load之前。
static void UserClkConfig()
{
    AP_PCRM->CLKHF_CTL1_f.DCLK32M_SEL = 0;
    AP_PCRM->CLKHF_CTL1_f.DCLK32M_EN = 1;     // 使能 DLL32M 时钟，ADC使用32M时钟分频后的1.28M时钟
#if (_MCU_SPIF_CLK_SEL == 3)
    AP_PCRM->CLKHF_CTL1_f.DCLK48M_EN = 1;   // 使能给 SPI FLASH 用
#endif
    // AP_PCRM->CLKHF_CTL1_f.DCLK64M_EN = 1; SDK已经使能
#if (_MCU_SPIF_CLK_SEL == 5)
    AP_PCRM->CLKHF_CTL1_f.DCLK96M_EN = 1;   // 使能给 SPI FLASH 用
#endif
#ifndef _MCU_DEBUG
    Wdt_Init();     // 使能开门狗解决FLASH时钟高于48M启动失败的问题。
#endif
    AP_PCRM->CLKSEL_f.SPIFCLK_SEL = _MCU_SPIF_CLK_SEL;      // 内置的 SPI FLASH 时钟源选择，直接影响性能，CPU频率（HCLK）影响不大（96M仅提高2%）
    // AP_PCRM->CLKSEL_f.HCLK_SEL = 5;  // CPU时钟 设置成96M蓝牙功能异常未找到原因 SDK配置中设置也是一样

    // 外设时钟配置
    // AP_PCR->SW_CLK =  默认全是开启的
}
